<template>
  <div class="validate-input-container pb-3">
    <input v-if="tag !== 'textarea'" type="text" 
            class="form-control" 
            :class="{'is-invalid': inputRef.error}"
            :value="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs">
    <textarea v-else 
            class="from-control"
            :class="{'is-invalid': inputRef.error}"
            :value="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs"></textarea>
    <span v-if="inputRef.error" class="invalid-feedback">{{ inputRef.message }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, PropType, reactive } from "vue";
import { emitter } from "./ValidateForm.vue";
// 用这正则来验证邮箱
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

interface RuleProp {
  // 就是你输入邮箱的，我们写的type 类型是一个必选邮箱，检测你输入的是不是邮箱
  type: "required" | "email" | 'custom';
  // 除了邮箱，用户名和密码也是必填的，所以在这个地方加一个扩展
  message: string;
  validator?: () => boolean
}

// RulesProp 就是在 RuleProp 基础上扩展的，也是遵循这个的
export type RulesProp = RuleProp[]

// 让这个组件支持文本域
export type TagType = 'input' | 'textarea'

export default defineComponent({
  name: "ValidateInput",
  props: {
    rules: Array as PropType<RulesProp>,
    modelValue: String,
    tag: {
      type: String as PropType<TagType>,
      default: 'input'
    }
  },
  setup(props, context) {
    const inputRef = reactive({
      // 如果他一开始就有值的话，在这个modelValue里面拿值
      // 如果你刷新页面你的 input 里面有值就是在页面中显示出来，显示出来props.modelValue
      // 如果没有值就是后面的情况
      val: props.modelValue || '', // 内容
      error: false, // 返回一个错误，需要给它一个错误信息
      message: "", // 信息提示
    });
    
    // 实现事件 
    // 往里面输入内容，鼠标只起到了失焦和获焦的作用
    // 输入的内容应该是键盘事件
    const updateValue = (e:KeyboardEvent) => {
      
        // 就是拿到你的事件源，根据你的事件源推断它是不是当前的元素，然后取这个value进行赋值就可以了
        const targetValue = (e.target as HTMLInputElement).value
        inputRef.val = targetValue
        // 不写下面的内容，双向数据绑定只能是完成一半的
        // 将改变之后的数据发送出去 传递给 父组件中的内容
        context.emit('value', targetValue)
    }
    
    // 失焦的事件
    const validateInput = () => {
        if(props.rules) { // 判断它里面是否有值
            const allPassed = props.rules.every(rule => {
                let passed = true
                inputRef.message = rule.message
                switch (rule.type) {
                    case 'required':
                        //  不为空才可以通过
                        passed = (inputRef.val.trim() !== '')
                    break;
                    case 'email': // 检测输入框里的内容
                        passed = emailReg.test(inputRef.val)
                    break;
                    case 'custom':
                        passed = rule.validator ? rule.validator() : true
                    break;
                    default:
                    break
                }
                // 将结果返回出去
                return passed
            })
            inputRef.error = !allPassed
            return allPassed
        }
    }
    
    onMounted(() => { // 去执行绑定的那个事件
      emitter.emit('form-item-created', validateInput)
    })
    return {
        inputRef,
        validateInput,
        updateValue
    };
  },
});
</script>
